6-OpenGL ES着色器语言
一、学习要点
本章稍作休息,暂时不实验WebGL示例程序,我们熟悉一下 OpenGL ES着色器语言,及其关键特性。
- 数据、变量和变量类型。
- 矢量、矩阵、结构体、数组、采样器(纹理)。
- 运算、程序流、函数
- attribute、uniform 和 varying 变量
- 精度限定词
- 预处理和质量。
二、你好 着色器 (hello word)
简单的着色器
// 顶点着色器
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_MvpMatrix;
varying vect v_Color;
void main(){
gl_Position = u_MvpMatrix * a_Position ;
v_Color = a_Color;
}
// 片元着色器
precision mediump float;
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
三、基础知识
- 程序是大小写敏感的(marina 和 Marina不同)。
- 每一个语句都应该以英文分号结束。
- 执行次序: 从main() 函数开始执行。main()函数不能有任何返回值,也不接收任何参数。
- 注释格式和JS相同。
四、 数据值类型(数值和 布尔值)
GLSL只支持两种数据值类型。不支持字符串
五、 变量
- 可以使用任何变量名,不能以保留字 和gl_ webgl_ webgl 开头就行。
六、 GLSL ES 是强类型语言
使用var 关键字来声明所有变量。必须具体指明变量类型。 声明方式是 <类型> <变量名> 如 vec4 a_Position
七、基本类型
float 单精度浮点数类型 int 整数 bool 布尔值
变量赋值的时候一定要注意等号两边的类型要相同,如果不相同就会报错。类型转换方式 float() 将整数转换成浮点数。
int i=8;
float f1 = float(i);
支持的转换函数有
- int(): 将浮点数小数部删去,true转换为1 false 转换成0
- float() : 整数转换成浮点数 true转换成1.0 false 转换成 0.0
- bool(): 0 转换成 false 非0转成 true
八、 矢量和矩阵
- 矢量类型: vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4
- 矩阵 mat2 mat3 mat4 构造函数赋值 如 vec4 position = vec4(1.0,2.0,3.0,4.0); 多个矢量合并成一个矢量 vec4 v4b = vec4(v2,v4) 规则是先把第一个参数的所有元素填进去 如果未填满,就继续使用第二额参数v4中的元素填充
- 矩阵构造函数
向矩阵构造函数中传入矩阵的每个元素的数值来构造矩阵,注意传入值的顺序必须是列主序。向矩阵中传入单个数值,会形成对小贤上元素都是该值 其他元素为0;
mat4 m4 = mat4( 1.0,2.0,3.0,4.0, 5.0,6.0,7.0,8.0, 9.0,10.0,11.0,12.0, 13.0,14.0,15.0,16.0 ); // 最后的矩阵结构是 1.0,5.0,9.0,13.0, // 2.0,6.0,10.0,14.0, // 3.0,7.0,11.0,15.0, // 4.0,8.0,12.0,16.0
九、访问元素
- 在矢量变量名后接点运算符(.)然后接上分两名,就可以访问矢量元素了。如下
- x,y,z,w 用来获取顶点坐标分量
- r,g,b,a 用来获取颜色分量
- s,t,p,q 用来获取纹理坐标分量
- 多个分量命共同置于运算符后 就可以从矢量中同时抽取多个分量。叫做(混合 swizzling)
- [] 需要注意的是不不能使用未经const修饰的变量作为索引值 除非他是循环索引
十、结构体
使用关键字 struct 将已存在的类型聚合到一起,就可以定义为结构体,比如
struct light{
vec4 color;
vec3 position;
}
light l1ml2
十一、 数组
与JavaScript不同 GLSL ES只支持一维数组。也不支持pop() 和 push() 等操作, 创建数组时也不需要使用new 运算符。声明时不需要new 运算符。例如
float floatArray[4]; vec4 vec4Array[2];
数组只支持[] 运算符 但数组的元素能够参与其自身类型支持的任意运算。比如 float f = floatArray[1] * 3.14;
数组下标不能是变量 只能是常量 或者 uniform变量
十二、取样器(纹理)
取样器(sampler)我们必须通过该类型变量访问纹理。有两种基本的取样器类型: sampler2D 和 samplerCube。取样器变量只能是uniform变量,或者需要访问纹理的函数,如texture2D() 函数。 如 uniform sampler2D u_Sampler;
- 取样器的复制必须要使用gl.uniformli()来进行赋值。
十三、程序流程控制 分支与循环。
- 分支使用 if else 控制 没有switch语句
- for 循环 和JS一样
- continue break 和 discard语句 discard只能在片元着色器中使用,表示放弃当前片元直接处理下一个片元 后续会具体讲到。
十四、函数
格式如下
返回类型 函数名 (type0 arg0, type1 arg1 ...){
函数计算
return 返回值
}
// 例如下代码 将RGBA颜色全置换为亮度值
float luma(vec4 color){
float r = color.r;
float g = color.g;
float b = color.b;
return 0.2126 * r + 0.7162 *g + 0.0772 *b
}
// 调用方法
attribute vec4 a_Color;
void main(){
float brightness = luma(a_Color);
}
规范声明: 如果函数定义在调用之后 一定要在调用前使用规范声明 如 float luma(vec4);
参数限定字:
- in 想函数中传入值,可以修改,但不会影响函数外面的变量
- 向函数中传入值,但是这个值不能修改
- out 在函数中被赋值,并被传出
- inout 传入函数,同时在函数中被赋值,并被传出。
- 没有限定 和in 一样
十五、 内置函数
十六、 全局变量和局部变量
和 js相同
十七、 存储限定字
attribute、varying 、 uniform 、const
Attribute变量
- 只能出现在顶点着色器中。
- 只能被声明为全局变量。
- 变量类型只能是 float vec2 vec3 vec4 mat2 mat3 mat5
- attribute的最大数目 gl_MaxVertexAttribs 最小值为 8
uniform变量
- 可以在顶点着色器和片元着色器中。
- uniform变量是只读的。
- 顶点着色器中最小个数 为 128 片元着色器中最小个数为 16
varying变量
- 必须是全局变量,从顶点着色器向片元着色器传输数据。
十八、 精度限定字
目的是提高运行效率,削减内存开支。
- precision mediump float(中等精度)
- precision highp float(高精度)
- precision lowp float(低精度)
- 每种类型都有默认精度,除了片元着色器中的float类型
十九、 指令预处理
#ifdef GL_ES
precision mediump float;
#endif
总结 本章主要是GLSL ES语言的核心特性,后续如果有疑问可以作为工具查询。 下一章正式进入三维的世界。